import _ from 'lodash';
import Konva from 'konva';
import React from 'react';
import { Stage } from 'react-konva';
import EmptyProps from '../types/EmptyProps';
import { randomString } from '../util';
import { DragContext } from './DragContex';
import HanziCard from './HanziCard';
import HanziList from './HanziList';
import { windowResizingObservable } from '../global';
import { Subscription } from 'rxjs';
import SentenceList from './SentenceList';
import PositionedHanzi from './model/PositionedHanzi';

type States = {
  dragContext: DragContext | null;
  hanzi: PositionedHanzi[];
  width: number;
  height: number;
};

class Application extends React.Component<EmptyProps, States> {
  stageRef: React.RefObject<Konva.Stage>;
  windowResizingSubscription: Subscription | null;

  constructor(props: EmptyProps) {
    super(props);
    this.state = {
      dragContext: null,
      hanzi: [],
      width: window.innerWidth, // TODO: hoc
      height: window.innerHeight,
    };
    this.stageRef = React.createRef();
    this.windowResizingSubscription = null;
  }

  componentDidMount(): void {
    this.windowResizingSubscription = windowResizingObservable.subscribe(
      (size) => this.setState({ width: size.width, height: size.height }) // TODO: 似乎不够精确
    );
  }

  componentWillUnmount(): void {
    this.windowResizingSubscription?.unsubscribe();
  }

  handleDropIn = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    const { dragContext } = this.state;
    if (dragContext == null) {
      return;
    }

    const stage = this.stageRef.current;
    if (stage) {
      stage.setPointersPositions(e);
      const positionedHanzi: PositionedHanzi = {
        id: randomString(),
        c: dragContext.c,
        x: stage.getPointerPosition()?.x || 0,
        y: stage.getPointerPosition()?.y || 0,
      };
      this.setState({ hanzi: [...this.state.hanzi, positionedHanzi] });
    }
    this.setState({ dragContext: null });
  };

  handelHanziCardDragEnd = (hz: PositionedHanzi) => {
    const { hanzi } = this.state;
    const newHanzi = _.cloneDeep(hanzi);
    for (const it of newHanzi) {
      if (it.id == hz.id) {
        it.x = hz.x;
        it.y = hz.y;
      }
    }

    this.setState({ hanzi: newHanzi });
  };

  render() {
    const { hanzi, width, height } = this.state;
    return (
      <div style={{ position: 'relative' }}>
        <div onDrop={this.handleDropIn} onDragOver={(e) => e.preventDefault()}>
          <Stage width={width} height={height} ref={this.stageRef}>
            {hanzi.map((it) => (
              <HanziCard
                key={it.id}
                c={it.c}
                x={it.x}
                y={it.y}
                onDragEnd={(e) => {
                  this.handelHanziCardDragEnd({ id: it.id, x: e.target.x(), y: e.target.y(), c: it.c });
                  const stage = this.stageRef.current;
                  if (stage) {
                    stage.container().style.cursor = 'pointer';
                  }
                }}
                onMouseEnter={(e) => {
                  const stage = this.stageRef.current;
                  if (stage) {
                    stage.container().style.cursor = 'pointer';
                  }
                }}
                onMouseLeave={(e) => {
                  const stage = this.stageRef.current;
                  if (stage) {
                    stage.container().style.cursor = 'default';
                  }
                }}
                onDragMove={(e) => {
                  const stage = this.stageRef.current;
                  if (stage) {
                    stage.container().style.cursor = 'grabbing';
                  }
                }}
              />
            ))}
          </Stage>
        </div>
        <div style={{ position: 'absolute', right: 4, top: 4 }}>
          <HanziList onDragStart={(context) => this.setState({ dragContext: context })} />
        </div>

        <div style={{ position: 'absolute', left: 4, top: 4 }}>
          <SentenceList
            onSaveSentence={(save) => save(hanzi)}
            onClickSentence={(s) => this.setState({ hanzi: s.hanziList })}
          />
        </div>
      </div>
    );
  }
}

export default Application;
